{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "torch.Size([4])\n"
     ]
    }
   ],
   "source": [
    "x = torch.arange(4)\n",
    "# 张量的长度\n",
    "print(len(x))\n",
    "# 张量的形状\n",
    "print(x.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 0,  1,  2,  3],\n",
      "        [ 4,  5,  6,  7],\n",
      "        [ 8,  9, 10, 11],\n",
      "        [12, 13, 14, 15],\n",
      "        [16, 17, 18, 19]])\n",
      "tensor([[ 0,  4,  8, 12, 16],\n",
      "        [ 1,  5,  9, 13, 17],\n",
      "        [ 2,  6, 10, 14, 18],\n",
      "        [ 3,  7, 11, 15, 19]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.arange(20).reshape(5, 4)\n",
    "print(x)\n",
    "# 矩阵的转置\n",
    "print(x.T)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1, 2, 3],\n",
      "        [2, 0, 4],\n",
      "        [3, 4, 5]])\n",
      "tensor([[1, 2, 3],\n",
      "        [2, 0, 4],\n",
      "        [3, 4, 5]])\n",
      "tensor([[True, True, True],\n",
      "        [True, True, True],\n",
      "        [True, True, True]])\n"
     ]
    }
   ],
   "source": [
    "# 作为方阵的一种特殊类型,对称矩阵（symmetric matrix）A等于其转置：A = A.T\n",
    "A = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])\n",
    "print(A)\n",
    "print(A.T)\n",
    "print(A == A.T)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[ 0,  1,  2,  3],\n",
       "         [ 4,  5,  6,  7],\n",
       "         [ 8,  9, 10, 11]],\n",
       "\n",
       "        [[12, 13, 14, 15],\n",
       "         [16, 17, 18, 19],\n",
       "         [20, 21, 22, 23]]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 当我们开始处理图像时，张量将变得更加重要，图像以n维数组形式出现，\n",
    "# 其中3个轴对应于高度、宽度，以及一个通道（channel）轴，\n",
    "# 用于表示颜色通道（红色、绿色和蓝色）\n",
    "x = torch.arange(24).reshape(2, 3, 4)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[ 0.,  1.,  2.,  3.],\n",
       "         [ 4.,  5.,  6.,  7.],\n",
       "         [ 8.,  9., 10., 11.],\n",
       "         [12., 13., 14., 15.],\n",
       "         [16., 17., 18., 19.]]),\n",
       " tensor([[ 0.,  2.,  4.,  6.],\n",
       "         [ 8., 10., 12., 14.],\n",
       "         [16., 18., 20., 22.],\n",
       "         [24., 26., 28., 30.],\n",
       "         [32., 34., 36., 38.]]))"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 给定具有相同形状的任意两个张量，任何按元素二元运算的结果都将是相同形状的张量\n",
    "a = torch.arange(20, dtype=torch.float32).reshape(5, -1)\n",
    "# 通过分配新内存，将A的一个副本分配给B\n",
    "b = a.clone()\n",
    "a, a+b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[  0.,   1.,   4.,   9.],\n",
       "        [ 16.,  25.,  36.,  49.],\n",
       "        [ 64.,  81., 100., 121.],\n",
       "        [144., 169., 196., 225.],\n",
       "        [256., 289., 324., 361.]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 两个矩阵的按元素乘法称为Hadamard积（Hadamard product)\n",
    "a * b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[[ 0,  1,  2,  3],\n",
       "          [ 4,  5,  6,  7],\n",
       "          [ 8,  9, 10, 11]],\n",
       " \n",
       "         [[12, 13, 14, 15],\n",
       "          [16, 17, 18, 19],\n",
       "          [20, 21, 22, 23]]]),\n",
       " tensor([[[ 2,  3,  4,  5],\n",
       "          [ 6,  7,  8,  9],\n",
       "          [10, 11, 12, 13]],\n",
       " \n",
       "         [[14, 15, 16, 17],\n",
       "          [18, 19, 20, 21],\n",
       "          [22, 23, 24, 25]]]),\n",
       " tensor([[[ 0,  2,  4,  6],\n",
       "          [ 8, 10, 12, 14],\n",
       "          [16, 18, 20, 22]],\n",
       " \n",
       "         [[24, 26, 28, 30],\n",
       "          [32, 34, 36, 38],\n",
       "          [40, 42, 44, 46]]]),\n",
       " torch.Size([2, 3, 4]))"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将张量乘以或加上一个标量不会改变张量的形状，其中张量的每个元素都将与标量相加或相乘\n",
    "a = 2\n",
    "b = torch.arange(24).reshape(2, 3, 4)\n",
    "b, a+b, a*b, (a*b).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([0., 1., 2., 3.]),\n",
       " tensor(6.),\n",
       " tensor([[0, 1, 2],\n",
       "         [3, 4, 5],\n",
       "         [6, 7, 8]]),\n",
       " tensor(36))"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 可以对任意张量进行的一个有用的操作是计算其元素的和\n",
    "x = torch.arange(4, dtype=torch.float32)\n",
    "y = torch.arange(9).reshape(3, -1)\n",
    "x, x.sum(), y, y.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[0, 1, 2],\n",
       "         [3, 4, 5],\n",
       "         [6, 7, 8]]),\n",
       " tensor([ 9, 12, 15]),\n",
       " torch.Size([3]),\n",
       " tensor([ 3, 12, 21]),\n",
       " torch.Size([3]),\n",
       " tensor(36))"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 默认情况下，调用求和函数会沿所有的轴降低张量的维度，使它变为一个标量。\n",
    "# 我们还可以指定张量沿哪一个轴来通过求和降低维度。 以矩阵为例，为了通过求和所有行的元素来降维（轴0\n",
    "# 我们可以在调用函数时指定axis=0。 由于输入矩阵沿0轴降维以生成输出向量，因此输入轴0的维数在输出形状中消失\n",
    "x = torch.arange(9).reshape(3, -1)\n",
    "# 0是竖着加,1是横着加\n",
    "x_sum_axis0 = x.sum(axis=0)\n",
    "x_sum_axis1 = x.sum(axis=1)\n",
    "# 沿着行和列对矩阵求和，等价于对矩阵的所有元素进行求和\n",
    "x_all = x.sum(axis=[0, 1])  # 相当于 s.sum()\n",
    "x, x_sum_axis0, x_sum_axis0.shape, x_sum_axis1, x_sum_axis1.shape, x_all"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[0., 1., 2.],\n",
       "         [3., 4., 5.],\n",
       "         [6., 7., 8.]]),\n",
       " tensor(4.),\n",
       " tensor(4.))"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 一个与求和相关的量是平均值（mean或average)\n",
    "# 我们通过将总和除以元素总数来计算平均值。 在代码中，我们可以调用函数来计算任意形状张量的平均值\n",
    "x = torch.arange(9, dtype=torch.float32).reshape(-1, 3)\n",
    "x, x.mean(), x.sum()/x.numel()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[0., 1., 2.],\n",
       "         [3., 4., 5.],\n",
       "         [6., 7., 8.]]),\n",
       " tensor([3., 4., 5.]),\n",
       " tensor([3., 4., 5.]))"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 同样，计算平均值的函数也可以沿指定轴降低张量的维度\n",
    "x, x.mean(axis=0), x.sum(axis=0) / x.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 3.],\n",
       "        [12.],\n",
       "        [21.]])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 有时在调用函数来计算总和或均值时保持轴数不变会很有用\n",
    "x_sum = x.sum(axis=1, keepdims=True)\n",
    "x_sum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.0000, 0.3333, 0.6667],\n",
       "        [0.2500, 0.3333, 0.4167],\n",
       "        [0.2857, 0.3333, 0.3810]])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 由于 x_sum 在对每行进行求和后仍保持两个轴，我们可以通过广播将 x 除以 x_sum\n",
    "x / x_sum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[0., 1., 2.],\n",
       "         [3., 4., 5.],\n",
       "         [6., 7., 8.]]),\n",
       " tensor([[ 0.,  1.,  2.],\n",
       "         [ 3.,  5.,  7.],\n",
       "         [ 9., 12., 15.]]),\n",
       " tensor([[ 0.,  1.,  3.],\n",
       "         [ 3.,  7., 12.],\n",
       "         [ 6., 13., 21.]]))"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果我们想沿某个轴计算A元素的累积总和， 比如axis=0（按行计算)\n",
    "# 我们可以调用cumsum函数。 此函数不会沿任何轴降低输入张量的维度\n",
    "x, x.cumsum(axis=0), x.cumsum(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([1., 1., 1., 1.]), tensor([0., 1., 2., 3.]), tensor(6.))"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 点积（Dot Product）\n",
    "x = torch.ones(4, dtype=torch.float32)\n",
    "y = torch.arange(4, dtype=torch.float32)\n",
    "x, y, torch.dot(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(6.)"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 可以通过执行按元素乘法，然后进行求和来表示两个向量的点积\n",
    "torch.sum(x * y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([5, 4]), torch.Size([4]), tensor([ 14.,  38.,  62.,  86., 110.]))"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 在代码中使用张量表示矩阵-向量积，我们使用与点积相同的mv函数。\n",
    "# 当我们为矩阵A和向量x调用torch.mv(A, x)时，会执行矩阵-向量积。\n",
    "# 注意，A的列维数（沿轴1的长度）必须与x的维数（其长度）相同。\n",
    "a = torch.arange(20, dtype=torch.float32).reshape(5, -1)\n",
    "b = torch.arange(4, dtype=torch.float32)\n",
    "a.shape, b.shape, torch.mv(a, b)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[ 0.,  1.,  2.,  3.],\n",
       "         [ 4.,  5.,  6.,  7.],\n",
       "         [ 8.,  9., 10., 11.],\n",
       "         [12., 13., 14., 15.],\n",
       "         [16., 17., 18., 19.]]),\n",
       " tensor([[1., 1., 1.],\n",
       "         [1., 1., 1.],\n",
       "         [1., 1., 1.],\n",
       "         [1., 1., 1.]]),\n",
       " tensor([[ 6.,  6.,  6.],\n",
       "         [22., 22., 22.],\n",
       "         [38., 38., 38.],\n",
       "         [54., 54., 54.],\n",
       "         [70., 70., 70.]]))"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 2个矩阵相乘\n",
    "c = torch.ones((4, 3), dtype=torch.float32)\n",
    "a, c, torch.mm(a, c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor(5.), tensor(7.))"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 范数(norm) 非正式地说，一个向量的范数告诉我们一个向量有多大。\n",
    "# 这里考虑的大小（size）概念不涉及维度，而是分量的大小。\n",
    "u = torch.tensor([3.0, -4.0])\n",
    "torch.norm(u), torch.abs(u).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[1., 1., 1., 1., 1., 1., 1., 1., 1.],\n",
       "         [1., 1., 1., 1., 1., 1., 1., 1., 1.],\n",
       "         [1., 1., 1., 1., 1., 1., 1., 1., 1.],\n",
       "         [1., 1., 1., 1., 1., 1., 1., 1., 1.]]),\n",
       " tensor(6.))"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Frobenius范数（Frobenius norm）是矩阵元素平方和的平方根\n",
    "a = torch.ones((4, 9))\n",
    "a, torch.norm(a)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.8.13 ('d2l')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "6bdcd3dff61cfecb093f68bfbd67338d4a9739a04d65268bf3b66287b86a0a9e"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
